package com.lehecai.ucenter.action.user;

import com.lehecai.core.YesNoStatus;
import com.lehecai.core.exception.cache.CacheException;
import com.lehecai.core.service.cache.CacheService;
import com.lehecai.core.util.CoreHttpUtils;
import com.lehecai.ucenter.action.BaseAction;
import com.lehecai.ucenter.bean.UserSessionBean;
import com.lehecai.ucenter.constant.GlobalConstant;
import com.lehecai.ucenter.entity.permission.Permission;
import com.lehecai.ucenter.entity.permission.Role;
import com.lehecai.ucenter.entity.permission.User;
import com.lehecai.ucenter.service.ServiceException;
import com.lehecai.ucenter.service.permission.PermissionService;
import com.lehecai.ucenter.service.permission.RoleService;
import com.lehecai.ucenter.service.permission.UserService;
import com.lehecai.ucenter.utils.GoogleAuthenticator;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletRequest;
import java.util.*;


public class LoginAction extends BaseAction {
	private static final long serialVersionUID = -8830679912602886965L;
	
	private UserService userService;
	private RoleService roleService;
	private PermissionService permissionService;
    private CacheService cacheService;
    private String cacheName;

    private Long uid;
	private String username;
	private String password;
	private String verifyCode;
    private String oneTimePassword;

	@SuppressWarnings("unchecked")
	public String handle() {
		logger.info("进入验证登录");
		if (StringUtils.isEmpty(username)) {
			logger.error("用户名为空");
			super.setErrorMessage("用户名不能为空");
			return "index";
		}
		if (StringUtils.isEmpty(password)) {
			logger.error("密码为空");
			super.setErrorMessage("密码不能为空");
			return "index";
		}
		if (StringUtils.isEmpty(verifyCode)) {
			logger.error("验证码为空");
			super.setErrorMessage("验证码不能为空");
			return "index";
		}

        HttpServletRequest request = ServletActionContext.getRequest();
        String kaptchaExpected = (String)request.getSession()
                .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        if (verifyCode == null || !verifyCode.equalsIgnoreCase(kaptchaExpected)) {
            logger.error("验证码错误");
            super.setErrorMessage("验证码错误");
            return "index";
        }
		
		User user = userService.login(username, password);
		if (user == null) {
			logger.error("用户名或密码错误,用户输入信息：username={}, password={}", new Object[] {username, password});
			super.setErrorMessage("用户名或密码错误");
			return "index";
		}

        if (user.getOtp().getValue() == YesNoStatus.YES.getValue()) {
            logger.info("用户[{}]已开启动态密码验证", user.getUsername());
            uid = user.getId();
            return "oneTimePassword";
        }
		
		Role role = userService.findRoleByUser(user);
		if(role == null){
			logger.error("获取用户角色错误，请联系管理员。");
			super.setErrorMessage("获取用户角色错误，请联系管理员。");
			return "index";
		}
		
		if (role.isRestriction()) {//限定ip时，进行有效ip段验证
			String[] remoteIp = getRemoteIp(ServletActionContext.getRequest());
			StringBuffer sb = new StringBuffer();
			for(int i = 0; i < remoteIp.length; i++){
				sb.append(remoteIp[i]);
			}
			if (!matchingIp(role.getRestrictionIp(), remoteIp)) {
				logger.error("IP地址无效，当前IP地址："+sb);
				super.setErrorMessage("您的IP地址无效");
				return "index";
			}
		}
		
		if (user.getLoginTime() != null) {
			user.setLastLoginTime(user.getLoginTime());
		}
		user.setLoginTime(new Date());
		try {
			userService.update(user);
		} catch (ServiceException e) {
			logger.error(e.getMessage());
			super.setErrorMessage(e.getMessage());
			return "failure";
		}
		
		//创建userSessionBean
		UserSessionBean userSessionBean = new UserSessionBean();
		//setUser
		userSessionBean.setUser(user);
		//serRole
		userSessionBean.setRole(role);
		
        // 一次性读出所有权限
        List<Permission> allPermissionList = permissionService.getAll();
        Map<Long, Permission> allPermissionMap = new HashMap<Long, Permission>();
        // 转置map
        if (allPermissionMap != null) {
            for (Permission permission : allPermissionList) {
            	allPermissionMap.put(permission.getId(), permission);
            }
        }

        List<Permission> havePermissionList = roleService.findPermissionsByRole(role);
		if (havePermissionList == null || havePermissionList.size() == 0) {
			logger.error("您所拥有的角色没有任何权限");
			super.setErrorMessage("您所拥有的角色没有任何权限，请联系管理员");
			return "index";
		}
		
		//按orderView排序 数值大的在前面
		Collections.sort(havePermissionList, new Comparator<Permission>() {
			public int compare(Permission arg0, Permission arg1) {
				return arg1.getOrderView().compareTo(arg0.getOrderView());
			}
		});
		
		userSessionBean.setPermissions(havePermissionList);
		super.getSession().put(GlobalConstant.USER_SESSION_KEY, userSessionBean);
		super.setForwardUrl("/main.do");
		logger.info("验证登录结束");
		return "forward";
	}

    public String secondVerify() {
        if (uid == null || uid <= 0L) {
            logger.error("ucenter登录二次验证uid参数为空");
            super.setErrorMessage("ucenter登录二次验证uid参数为空");
            return "index";
        }

        if (StringUtils.isEmpty(oneTimePassword)) {
            logger.error("ucenter登录二次验证oneTimePassword参数为空");
            super.setErrorMessage("ucenter登录二次验证oneTimePassword参数为空");
            return "index";
        }

        User user = userService.get(uid);

        //验证动态密码
        String cachedOneTimePassword = null;
        try {
            cachedOneTimePassword = cacheService.getObject(String.class, cacheName, oneTimePassword);
        } catch (CacheException e) {
            logger.error("从缓存中读取动态密码出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        if (!StringUtils.isEmpty(cachedOneTimePassword)) {
            String msg = String.format("动态密码已被使用:username=%s, cachedOneTimePassword=%s", user.getUsername(), cachedOneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            return "index";
        }

        long t = System.currentTimeMillis();
        GoogleAuthenticator ga = new GoogleAuthenticator();
        ga.setWindowSize(5);  //should give 5 * 30 seconds of grace...

        long code = 0L;
        try {
            code = Long.parseLong(oneTimePassword);
        } catch (NumberFormatException e) {
            String msg = String.format("动态密码格式不正确，转换成long错误:username=%s, password=%s", user.getUsername(), oneTimePassword);
            logger.error(msg);
            logger.error(e.getMessage(), e);
            super.setErrorMessage(msg);
            return "index";
        }

        boolean r = ga.check_code(user.getSecretKey(), code, t);
        if (!r) {
            String msg = String.format("动态密码不正确:username=%s, otp=%s", user.getUsername(), oneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            return "index";
        }

        try {
            cacheService.setObject(cacheName, oneTimePassword, oneTimePassword);
        } catch (CacheException e) {
            logger.error("设置缓存出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        logger.info("用户身份认证通过！username={}",  user.getUsername());
        Role role = userService.findRoleByUser(user);
        if(role == null){
            logger.error("获取用户角色错误，请联系管理员。");
            super.setErrorMessage("获取用户角色错误，请联系管理员。");
            return "index";
        }

        if (role.isRestriction()) {//限定ip时，进行有效ip段验证
            String[] remoteIp = getRemoteIp(ServletActionContext.getRequest());
            StringBuffer sb = new StringBuffer();
            for(int i = 0; i < remoteIp.length; i++){
                sb.append(remoteIp[i]);
            }
            if (!matchingIp(role.getRestrictionIp(), remoteIp)) {
                logger.error("IP地址无效，当前IP地址："+sb);
                super.setErrorMessage("您的IP地址无效");
                return "index";
            }
        }

        if (user.getLoginTime() != null) {
            user.setLastLoginTime(user.getLoginTime());
        }
        user.setLoginTime(new Date());
        try {
            userService.update(user);
        } catch (ServiceException e) {
            logger.error(e.getMessage());
            super.setErrorMessage(e.getMessage());
            return "failure";
        }

        //创建userSessionBean
        UserSessionBean userSessionBean = new UserSessionBean();
        //setUser
        userSessionBean.setUser(user);
        //serRole
        userSessionBean.setRole(role);

        // 一次性读出所有权限
        List<Permission> allPermissionList = permissionService.getAll();
        Map<Long, Permission> allPermissionMap = new HashMap<Long, Permission>();
        // 转置map
        if (allPermissionMap != null) {
            for (Permission permission : allPermissionList) {
                allPermissionMap.put(permission.getId(), permission);
            }
        }

        List<Permission> havePermissionList = roleService.findPermissionsByRole(role);
        if (havePermissionList == null || havePermissionList.size() == 0) {
            logger.error("您所拥有的角色没有任何权限");
            super.setErrorMessage("您所拥有的角色没有任何权限，请联系管理员");
            return "index";
        }

        //按orderView排序 数值大的在前面
        Collections.sort(havePermissionList, new Comparator<Permission>() {
            public int compare(Permission arg0, Permission arg1) {
                return arg1.getOrderView().compareTo(arg0.getOrderView());
            }
        });

        userSessionBean.setPermissions(havePermissionList);
        super.getSession().put(GlobalConstant.USER_SESSION_KEY, userSessionBean);
        super.setForwardUrl("/main.do");
        logger.info("验证登录结束");
        return "forward";
    }
	
	//获取访问者IP
	private String[] getRemoteIp(HttpServletRequest request) {
		String[] clientIPArray = CoreHttpUtils.getClientIPArray(request);
		if (clientIPArray != null && clientIPArray.length > 0) {
			return clientIPArray;
		}
		return null;
	}

	//ip段匹配
	private boolean matchingIp(String restrictionIp, String[] remoteIp) {
		//有效ip段或请求ip不存在
		if (restrictionIp == null || remoteIp == null) {
			return false;
		}
		
		for(int j = 0; j < remoteIp.length; j++){
			String[] restrictionIpArray = restrictionIp.trim().split(",");
			String[] remoteIpItem = remoteIp[j].trim().split("\\.");
			if (restrictionIpArray.length > 0) {
				for (String restrictionIpSegment : restrictionIpArray) {
					String[] restrictionIpItem = restrictionIpSegment.trim().split("\\.");
					if (restrictionIpItem.length == 4 && remoteIpItem.length == 4) {
						boolean flag = true;
						for (int i = 0; i < 4; i++) {
							if (!restrictionIpItem[i].equals("*") && !restrictionIpItem[i].equals(remoteIpItem[i])) {
								flag = false;
								break;
							}
						}
						if (flag) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getVerifyCode() {
		return verifyCode;
	}

	public void setVerifyCode(String verifyCode) {
		this.verifyCode = verifyCode;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public RoleService getRoleService() {
		return roleService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	public PermissionService getPermissionService() {
		return permissionService;
	}

	public void setPermissionService(PermissionService permissionService) {
		this.permissionService = permissionService;
	}

    public Long getUid() {
        return uid;
    }

    public void setUid(Long uid) {
        this.uid = uid;
    }

    public String getOneTimePassword() {
        return oneTimePassword;
    }

    public void setOneTimePassword(String oneTimePassword) {
        this.oneTimePassword = oneTimePassword;
    }

    public CacheService getCacheService() {
        return cacheService;
    }

    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }
}
